package com.ebupt.migu.fineoperationmedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.ebupt.migu.fineoperationmedia.common.JavaBeanConvertUtil;
import com.ebupt.migu.fineoperationmedia.entity.ApiQueryBean;
import com.ebupt.migu.fineoperationmedia.entity.response.ResDataBean;
import com.ebupt.migu.fineoperationmedia.entity.response.ResponseBean;
import com.ebupt.migu.fineoperationmedia.service.ApiQueryService;
import com.ebupt.migu.globalpopup.enums.IdentifierEnum;
import com.ebupt.migu.mediadata.pojo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * @author liuyangyang@e-byte.com
 * @description: TODO
 * @date 2024/4/16 16:45
 */
@Slf4j
@Service
public class ApiQueryServiceImpl implements ApiQueryService {

    /**
     * 当前用户上次请求的返回值，后面需要拼接请求参数中的deviceId（金刚区的返回值）
     */
    private static final String MEDIA_RESPONSE_KING_PREFIX = "MEDIA_RESPONSE_KING_";
    /**
     * 当前用户上次请求的返回值，后面需要拼接请求参数中的deviceId（侧边栏的返回值）
     */
    private static final String MEDIA_RESPONSE_BLOCK_PREFIX = "MEDIA_RESPONSE_BLOCK_";

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 查询指定栏位活动配置信息（bean.point）： 1- 侧边栏内容分区&侧边栏Banner； 2- 金刚区；
     *
     * @param bean
     * @return
     */
    @Override
    public ResponseBean query(ApiQueryBean bean) {
        log.info("request params:{}", bean);
        if (null == bean.getExtra()) {
            HashMap<String, String> extra = new HashMap<>();
            extra.put("login", "0");
            bean.setExtra(extra);
        } else if (null == bean.getExtra().get("uid") || String.valueOf(bean.getExtra().get("uid")).trim().isEmpty()) {
            bean.getExtra().put("login", "0");
        } else {
            bean.getExtra().put("login", "1");
        }
        ResponseBean response = new ResponseBean();
        List<MediaRedisBean> medias = new ArrayList<>();
        // 1-侧边栏内容分区&侧边栏Banner； 2-金刚区
        switch (bean.getPoint()) {
            case 1:
                // 未经排序的侧边栏活动
                List<MediaRedisBean> unSortedBlocks = new ArrayList<>();
                // 过滤侧边栏活动
                Set<String> blockActivities = redisTemplate.opsForSet().members(MediaConstants.MEDIA_BLOCK_ACTIVITIES);
                if (blockActivities != null && blockActivities.size() > 0) {
                    blockActivities.forEach(activity -> {
                        List<BlockBean> aimedBlocks = new ArrayList<>();
                        // 获取活动配置详情
                        MediaRedisBean media = JSON.parseObject(
                            String.valueOf(redisTemplate.opsForValue().get(activity)), MediaRedisBean.class);
                        // blocks参数不可为空
                        if (null == media || media.getBlocks().isEmpty()) {
                            return;
                        }
                        log.info("{}，media info：{}", bean.getTimestamp(), media);
                        media.getBlocks().stream().filter(block -> !block.getEntries().isEmpty()).forEach(block -> {
                            List<EntryBean> aimedEntries = new ArrayList<>();
                            // 条件筛选
                            aimedEntries.addAll(block.getEntries().stream().filter(entry -> entry.getMode() == 1)
                                .filter(entry -> ruleFilter(entry.getRules(), bean.getExtra(), bean.getTimestamp()))
                                .collect(Collectors.toList()));
                            // 客群归属
                            aimedEntries.addAll(block.getEntries().stream().filter(entry -> entry.getMode() == 2)
                                .filter(entry -> customerFilter(entry.getCustomerId(), bean.getExtra()))
                                .collect(Collectors.toList()));
                            // 保存符合筛选条件的分组
                            if (!aimedEntries.isEmpty()) {
                                BlockBean aimedBlock = new BlockBean();
                                aimedBlock.setBlockId(block.getBlockId());
                                aimedBlock.setBlockName(block.getBlockName());
                                aimedBlock.setBlockRank(block.getBlockRank());
                                aimedBlock.setEntries(
                                    aimedEntries.stream().sorted(Comparator.comparing(EntryBean::getEntryRank))
                                        .collect(Collectors.toList()));
                                aimedBlocks.add(aimedBlock);
                            }
                        });
                        // 保存符合筛选条件的配置
                        if (!aimedBlocks.isEmpty()) {
                            MediaRedisBean aimedMedia = new MediaRedisBean();
                            aimedMedia.setActivityId(media.getActivityId());
                            aimedMedia.setActivityName(media.getActivityName());
                            aimedMedia.setId(media.getId());
                            aimedMedia.setPriority(media.getPriority());
                            aimedMedia.setBlocks(aimedBlocks.stream()
                                .sorted(Comparator.comparing(BlockBean::getBlockRank)).collect(Collectors.toList()));
                            unSortedBlocks.add(aimedMedia);
                        }
                    });
                }
                // 排序规则：
                medias.addAll(unSortedBlocks.stream().sorted(Comparator.comparing(MediaRedisBean::getPriority)).limit(1)
                    .collect(Collectors.toList()));
                // 未经排序的侧边栏活动
                List<MediaRedisBean> unSortedBanners = new ArrayList<>();
                // 过滤Banner活动
                Set<String> bannerActivities =
                    redisTemplate.opsForSet().members(MediaConstants.MEDIA_BANNER_ACTIVITIES);
                if (bannerActivities != null && bannerActivities.size() > 0) {
                    bannerActivities.forEach(activity -> {
                        List<BannerBean> aimedBanners = new ArrayList<>();
                        // 获取活动配置详情
                        MediaRedisBean media = JSON.parseObject(
                            String.valueOf(redisTemplate.opsForValue().get(activity)), MediaRedisBean.class);
                        // banners参数不可为空
                        if (null == media || media.getBanners().isEmpty()) {
                            return;
                        }
                        log.info("{}，media info：{}", bean.getTimestamp(), media);
                        // 条件筛选
                        aimedBanners.addAll(media.getBanners().stream().filter(banner -> banner.getMode() == 1)
                            .filter(banner -> ruleFilter(banner.getRules(), bean.getExtra(), bean.getTimestamp()))
                            .collect(Collectors.toList()));
                        // 客群归属
                        aimedBanners.addAll(media.getBanners().stream().filter(banner -> banner.getMode() == 2)
                            .filter(banner -> customerFilter(banner.getCustomerId(), bean.getExtra()))
                            .collect(Collectors.toList()));
                        // 保存符合筛选条件的配置
                        if (!aimedBanners.isEmpty()) {
                            MediaRedisBean aimedMedia = new MediaRedisBean();
                            aimedMedia.setActivityId(media.getActivityId());
                            aimedMedia.setActivityName(media.getActivityName());
                            aimedMedia.setId(media.getId());
                            aimedMedia.setPriority(media.getPriority());
                            aimedMedia.setBanners(aimedBanners.stream()
                                .sorted(Comparator.comparing(BannerBean::getRank)).collect(Collectors.toList()));
                            unSortedBanners.add(aimedMedia);
                        }
                    });
                }
                // 排序规则：
                medias.addAll(unSortedBanners.stream().filter(activity -> !activity.getBanners().isEmpty())
                    .sorted(Comparator.comparing(MediaRedisBean::getPriority)).limit(1).collect(Collectors.toList()));
                break;
            case 2:
                // 未经排序的侧边栏活动
                List<MediaRedisBean> unSortedKings = new ArrayList<>();
                // 过滤金刚区活动
                Set<String> kingActivities = redisTemplate.opsForSet().members(MediaConstants.MEDIA_KING_ACTIVITIES);
                if (kingActivities != null && kingActivities.size() > 0) {
                    kingActivities.forEach(activity -> {
                        List<KingBean> aimedKings = new ArrayList<>();
                        // 获取活动配置详情
                        MediaRedisBean media = JSON.parseObject(
                            String.valueOf(redisTemplate.opsForValue().get(activity)), MediaRedisBean.class);
                        // kings参数不可为空
                        if (null == media || media.getKings().isEmpty()) {
                            return;
                        }
                        log.info("{}，media info：{}", bean.getTimestamp(), media);
                        // 条件筛选
                        aimedKings.addAll(media.getKings().stream().filter(king -> king.getMode() == 1)
                            .filter(king -> ruleFilter(king.getRules(), bean.getExtra(), bean.getTimestamp()))
                            .collect(Collectors.toList()));
                        // 客群归属
                        aimedKings.addAll(media.getKings().stream().filter(king -> king.getMode() == 2)
                            .filter(king -> customerFilter(king.getCustomerId(), bean.getExtra()))
                            .collect(Collectors.toList()));
                        // 保存符合筛选条件的配置
                        if (!aimedKings.isEmpty()) {
                            MediaRedisBean aimedMedia = new MediaRedisBean();
                            aimedMedia.setActivityId(media.getActivityId());
                            aimedMedia.setActivityName(media.getActivityName());
                            aimedMedia.setId(media.getId());
                            aimedMedia.setPriority(media.getPriority());
                            aimedMedia.setKings(aimedKings.stream().sorted(Comparator.comparing(KingBean::getEntryRank))
                                .collect(Collectors.toList()));
                            unSortedKings.add(aimedMedia);
                        }
                    });
                }
                medias.addAll(unSortedKings.stream().sorted(Comparator.comparing(MediaRedisBean::getPriority)).limit(1)
                    .collect(Collectors.toList()));
                break;
            default:
                break;
        }
        response.setCode("0000");
        response.setMessage("success");
        List<ResDataBean> resDataBeans =
            medias.stream().map(JavaBeanConvertUtil::mediaRedisBeanConvertToResDataBean).collect(Collectors.toList());
        // 缓存返回内容,并比较两次内容是否有差异
        boolean updata = false;
        if (bean.getPoint() == 1) {
            updata = hasRedisKey(bean, resDataBeans.toString(), MEDIA_RESPONSE_BLOCK_PREFIX);
        }
        if (bean.getPoint() == 2) {
            updata = hasRedisKey(bean, resDataBeans.toString(), MEDIA_RESPONSE_KING_PREFIX);
        }
        response.setData(resDataBeans);
        response.setTimestamp(bean.getTimestamp());
        response.setUpdate(updata);
        return response;
    }

    /**
     * 缓存返回内容,并比较两次内容是否有差异
     * 
     * @param bean
     * @param mediaResponseBlockPrefix
     * @return
     */
    private boolean hasRedisKey(ApiQueryBean bean, String data, String mediaResponseBlockPrefix) {
        boolean updata;
        if (Boolean.FALSE.equals(redisTemplate.hasKey(mediaResponseBlockPrefix + bean.getDeviceId()))) {
            updata = true;
        } else {
            updata = redisTemplate.opsForValue().get(mediaResponseBlockPrefix + bean.getDeviceId()).equals(data) ? false
                : true;
        }
        redisTemplate.opsForValue().set(mediaResponseBlockPrefix + bean.getDeviceId(), data, 7 * 24 * 60 * 60,
            TimeUnit.SECONDS);
        return updata;
    }

    /**
     * 条件筛选过滤：指定客群包含关系过滤
     *
     * @param extra
     * @return
     */
    private boolean customerFilter(String customerId, HashMap<String, String> extra) {
        String uid = Optional.ofNullable(extra.get("uid")).isPresent() ? extra.get("uid") : "";
        String msisdn = Optional.ofNullable(extra.get("msisdn")).isPresent() ? extra.get("msisdn") : "";
        if (redisTemplate.opsForSet().isMember(customerId + "-uid", uid)
            || redisTemplate.opsForSet().isMember(customerId + "-phone", msisdn)) {
            return true;
        }
        return false;
    }

    /**
     * 条件筛选过滤：筛选条件过滤
     * 
     * @param rules
     * @param extra
     * @return
     */
    private boolean ruleFilter(List<RuleBean> rules, HashMap<String, String> extra, String timestamp) {
        AtomicBoolean atomic = new AtomicBoolean(true);
        if (null == rules || rules.isEmpty()) {
            return true;
        }
        try {
            rules.forEach(rule -> {
                String value = extra.get(rule.getRuleKey());
                if (null == value || value.isEmpty()) {
                    atomic.set(false);
                    log.info("{}，筛选条件：{}，筛选值：{}，筛选规则：{}，传入参数值：{}, 判定结果：{}", timestamp, rule.getRuleKey(),
                        rule.getRuleValue(), rule.getOperator(), value, "false");
                    return;
                }
                switch (rule.getOperator()) {
                    // 等于
                    case 1:
                        if (!value.equals(rule.getRuleValue())) {
                            log.info("{}，筛选条件：{}，筛选值：{}，筛选规则：{}，传入参数值：{}, 判定结果：{}", timestamp, rule.getRuleKey(),
                                rule.getRuleValue(), rule.getOperator(), value, "false");
                            atomic.set(false);
                        }
                        break;
                    // 小于
                    case 2:
                        if (value.compareTo(rule.getRuleValue()) >= 0) {
                            log.info("{}，筛选条件：{}，筛选值：{}，筛选规则：{}，传入参数值：{}, 判定结果：{}", timestamp, rule.getRuleKey(),
                                rule.getRuleValue(), rule.getOperator(), value, "false");
                            atomic.set(false);
                        }
                        break;
                    // 大于
                    case 3:
                        if (value.compareTo(rule.getRuleValue()) <= 0) {
                            log.info("{}，筛选条件：{}，筛选值：{}，筛选规则：{}，传入参数值：{}, 判定结果：{}", timestamp, rule.getRuleKey(),
                                rule.getRuleValue(), rule.getOperator(), value, "false");
                            atomic.set(false);
                        }
                        break;
                    // 小于等于
                    case 4:
                        if (value.compareTo(rule.getRuleValue()) > 0) {
                            log.info("{}，筛选条件：{}，筛选值：{}，筛选规则：{}，传入参数值：{}, 判定结果：{}", timestamp, rule.getRuleKey(),
                                rule.getRuleValue(), rule.getOperator(), value, "false");
                            atomic.set(false);
                        }
                        break;
                    // 大于等于
                    case 5:
                        if (value.compareTo(rule.getRuleValue()) < 0) {
                            log.info("{}，筛选条件：{}，筛选值：{}，筛选规则：{}，传入参数值：{}, 判定结果：{}", timestamp, rule.getRuleKey(),
                                rule.getRuleValue(), rule.getOperator(), value, "false");
                            atomic.set(false);
                        }
                        break;
                    // 不等于
                    case 6:
                        if (value.equals(rule.getRuleValue())) {
                            log.info("{}，筛选条件：{}，筛选值：{}，筛选规则：{}，传入参数值：{}, 判定结果：{}", timestamp, rule.getRuleKey(),
                                rule.getRuleValue(), rule.getOperator(), value, "false");
                            atomic.set(false);
                        }
                        break;
                    default:
                        atomic.set(false);
                }
            });
            log.info("{}，判定结果：{}", timestamp, atomic.get());
            return atomic.get();
        } catch (Exception e) {
            return false;
        }
    }
}